package com.fengniaoxls.fengniaonewretail.jpush.voice;

import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.media.audiofx.LoudnessEnhancer;
import android.net.Uri;
import android.os.Build;

import com.fengniaoxls.fengniaonewretail.app.App;

import com.fengniaoxls.fengniaonewretail.utils.ThreadPoolProxy;
import com.fengniaoxls.fengniaonewretail.utils.ThreadPoolProxyFactory;
import com.freak.httphelper.log.LogUtil;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 音频播放类
 *
 * @author Administrator
 * @date 2018/10/9
 */

public class VoiceSpeaker {

    private static VoiceSpeaker sInstance;

    //    private ExecutorService service;
    private static ThreadPoolProxy service;
    private ConcatenatingMediaSource mConcatenatingMediaSource;

    private List<MediaSource> mMediaSourceList;
    // 定义音频响度处理类
    private LoudnessEnhancer loudnessEnhancer;

    private VoiceSpeaker() {
//        service = Executors.newCachedThreadPool();
        service = ThreadPoolProxyFactory.getNormalThreadPoolProxy();
    }

    /**
     * 获取音频播放对象
     *
     * @return
     */
    public static synchronized VoiceSpeaker getInstance() {
        if (sInstance == null) {
            sInstance = new VoiceSpeaker();
        }
        return sInstance;
    }


    /**
     * 播放前检查
     *
     * @param list
     */
    public void speak(final List<String> list) {
        if (service != null) {
            service.execute(new Runnable() {
                @Override
                public void run() {
//                    start(list);
                    LogUtil.e("播报语音");
                    exoPlayerStart(list);
                }
            });
        }
    }

    private synchronized void exoPlayerStart(final List<String> list) {
        synchronized (this) {
            if (mMediaSourceList == null) {
                mMediaSourceList = new ArrayList<>();
            }
            mMediaSourceList.clear();
            //并发
            final CountDownLatch latch = new CountDownLatch(1);
            DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(App.getInstance().getApplicationContext(),
                    Util.getUserAgent(App.getInstance().getApplicationContext(), "App"));
            final SimpleExoPlayer mPlayer = ExoPlayerFactory.newSimpleInstance(App.getInstance().getApplicationContext());
            for (int i = 0; i < list.size(); i++) {
                MediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(FileUtils.getAssetsPath(String.format("sound/tts_%s.mp3", list.get(i)))));
                mMediaSourceList.add(mediaSource);
            }

            switch (mMediaSourceList.size()) {
                case 1:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0));
                    break;
                case 2:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1));
                    break;
                case 3:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2));
                    break;
                case 4:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3));
                    break;
                case 5:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4));
                    break;
                case 6:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5));
                    break;
                case 7:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6));
                    break;
                case 8:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7));
                    break;
                case 9:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8));
                    break;
                case 10:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9));
                    break;
                case 11:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10));
                    break;
                case 12:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11));
                    break;
                case 13:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12));
                    break;
                case 14:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13));
                    break;
                case 15:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14));
                    break;
                case 16:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15));
                    break;
                case 17:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16));
                    break;
                case 18:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17));
                    break;
                case 19:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18));
                    break;
                case 20:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19));
                    break;
                case 21:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20));
                    break;
                case 22:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21));
                    break;
                case 23:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21),
                            mMediaSourceList.get(22));
                    break;
                case 24:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21),
                            mMediaSourceList.get(22), mMediaSourceList.get(23));
                    break;
                case 25:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21),
                            mMediaSourceList.get(22), mMediaSourceList.get(23), mMediaSourceList.get(24));
                    break;
                case 26:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21),
                            mMediaSourceList.get(22), mMediaSourceList.get(23), mMediaSourceList.get(24), mMediaSourceList.get(25));
                    break;
                case 27:
                    mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),
                            mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),
                            mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),
                            mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21),
                            mMediaSourceList.get(22), mMediaSourceList.get(23), mMediaSourceList.get(24), mMediaSourceList.get(25), mMediaSourceList.get(26));
                    break;
                default:
                    break;
            }


            mPlayer.addListener(new Player.EventListener() {
                @Override
                public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

                    if (playbackState == 4) {
                        mPlayer.release();
                        latch.countDown();
                    }
//                    if (playWhenReady) {
//                        LogUtil.e("mPlayer.getAudioSessionId() " + mPlayer.getAudioSessionId());
//                        try {
//                            loudnessEnhancer = new LoudnessEnhancer(mPlayer.getAudioSessionId());
//                            //设置用于音频效果的目标增益
//                            loudnessEnhancer.setTargetGain(2000);
//                            loudnessEnhancer.setEnabled(true);
//                        } catch (RuntimeException e) {
//                            e.printStackTrace();
//                        }
//                    }

                }

                @Override
                public void onPlayerError(ExoPlaybackException error) {
                    mPlayer.release();
                    latch.countDown();
                    // 释放所有对象
//                    loudnessEnhancer.release();
                }
            });


            mPlayer.prepare(mConcatenatingMediaSource);
            mPlayer.setPlayWhenReady(true);
            try {
                latch.await();
                this.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 开始播放
     *
     * @param list
     */
    private void start(final List<String> list) {
        synchronized (this) {
            //并发
            final CountDownLatch latch = new CountDownLatch(1);
            final MediaPlayer player = new MediaPlayer();
            /**
             * 遍历音频模板集合，按顺序播放音频文件
             */
            if (list != null && list.size() > 0) {
                final int[] counter = {0};
                /**
                 * format方法使用占位符进行格式化
                 * %s中的 s 代表 字符串类型
                 *
                 * path是音频文件的路径，通过格式化之后匹配到对应的音频文件
                 */
                String path = String.format("sound/tts_%s.mp3", list.get(counter[0]));
                AssetFileDescriptor fd = null;
                try {
                    fd = FileUtils.getAssetFileDescription(path);
                    /**
                     * 设置要使用的数据源（FileDescriptor）。FileDescriptor必须是可搜索的（注意，LocalSocket不可搜索）。调用者有责任关闭文件描述符。
                     * 参数说明：
                     * 第一个参数：FileDescriptor：您要播放的文件的FileDescriptor
                     * 第二个参数：long：要播放的数据开始的文件的偏移量，以字节为单位
                     * 第三个参数：long：要播放的数据的字节长度
                     */
                    player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(),
                            fd.getLength());
                    /**
                     * 准备播放器以异步方式播放。设置数据源和显示表面后，您需要调用prepare（）或prepareAsync（）。
                     * 对于流，您应该调用prepareAsync（），它会立即返回，而不是阻塞，直到缓冲了足够的数据。
                     */
                    player.prepareAsync();
                    /**
                     * 注册媒体源准备播放时要调用的回调。
                     */
                    player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mp.start();
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                if (player.isPlaying()) {
                                    player.setPlaybackParams(player.getPlaybackParams().setSpeed((float) 1.6));
                                }
                            }
                        }
                    });
                    /**
                     * 注册在回放期间到达媒体源末尾时要调用的回调。
                     */
                    player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mp) {

                            /**
                             * 将MediaPlayer重置为未初始化状态。调用此方法后，您必须通过设置数据源并调用prepare（）再次初始化它。
                             */
                            mp.reset();
                            counter[0]++;
                            if (counter[0] < list.size()) {
                                try {
                                    AssetFileDescriptor fileDescriptor = FileUtils.getAssetFileDescription(String.format("sound/tts_%s.mp3", list.get(counter[0])));
                                    mp.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());
                                    mp.prepare();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    latch.countDown();//完成预期工作，发出完成信号...
                                }
                            } else {
                                /**
                                 * 是否MediaPlayer资源
                                 */
                                mp.release();
                                latch.countDown();//完成预期工作，发出完成信号...
                            }
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                    latch.countDown();//完成预期工作，发出完成信号...
                } finally {
                    if (fd != null) {
                        try {
                            fd.close();//关闭文件操作
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            try {
                latch.await();////等待主线程执行完毕，获得开始执行信号...
                this.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void closeLoudnessEnhancer() {
//        if (loudnessEnhancer != null) {
//            loudnessEnhancer.release();
//        }
    }
}
